<?php
namespace app\common\library;
use Exception;

/**
 * @author 河南邦耀网络科技
 * @copyright Copyright (c) 2018 HNBY Network Technology Co., Ltd.
 * @link http://www.hnbangyao.com
 */
class Aop
{
    const API_URL = "https://openapi.alipay.com/gateway.do";
    public $appid = "";
    public $privKey = "";
    public $version = "1.0";
    public $signType = "RSA2";
    public $charset = "utf-8";
    public $format = "JSON";

    public function __construct()
    {
        $this->appId = \think\config::get("site.alipayappid"); //支付宝app_id
        $this->privKey = \think\config::get("site.alipayprivkey"); //支付宝秘钥
        if (empty($this->appId)) {
            throw new Exception('支付宝: 参数缺失appId');
        }
        if (empty($this->privKey)) {
            throw new Exception('支付宝: 参数缺失privKey');
        }
        $this->timestamp = date('Y-m-d H:i:s', time());
    }
    /**
     * init
     */
    public function init($info)
    {
        $data = [
            'outer_order_no' => $info['orderId'],
            'biz_code' => 'FACE',
            'identity_param' => [
                'identity_type' => "CERT_INFO",
                'cert_type' => "IDENTITY_CARD",
                'cert_name' => $info['username'],
                'cert_no' => $info['idcard'],
            ],
            'merchant_config' => [
                "return_url"=>"123"
            ],
        ];
        return $this->run("alipay.user.certify.open.initialize",$data);
    }
    /**
     * 获取授权链接
     */
    public function getUrl($certify_id)
    {
        $data = [
            'certify_id' => $certify_id
        ];
        return $this->run("alipay.user.certify.open.certify",$data);
    }
    /**
     * 获取授权信息
     */
    public function getInfo($certify_id)
    {
        $data = [
            'certify_id' => $certify_id
        ];
        return $this->run("alipay.user.certify.open.query",$data);
    }
    /**
     * 退款操作
     */
    public function refund($data)
    {
        return $this->run("alipay.trade.refund",$data);
    }
    /**
     * @return mixed
     * @throws Exception
     */
    public function run($method,$data)
    {
        $sysParams = [
            'app_id' => $this->appId,
            'method' => $method,
            'format' => $this->format,
            'charset' => $this->charset,
            'sign_type' => $this->signType,
            'timestamp' => (string)$this->timestamp,
            'version' => $this->version,
            'biz_content' => json_encode($data,JSON_UNESCAPED_UNICODE),
        ];
        $sysParams['sign'] = $this->sign($sysParams);
        if($method == 'alipay.user.certify.open.certify'){
            $url = self::API_URL."?".$this->urlEncodeArray($sysParams);
            return $url;
        }
        try {
            $methodType = str_replace(".", "_", $method);
            $result = \fast\Http::get(self::API_URL."?".$this->urlEncodeArray($sysParams));
            $result = json_decode($result, true);
            if (empty($result) || empty($result[$methodType.'_response'])) {
                throw new Exception('支付宝网络故障，请联系管理员或稍后重试');
            }
            if ($result[$methodType.'_response']['code'] != 10000) {
                throw new Exception($result[$methodType.'_response']['sub_msg']);
            }
            return $result[$methodType.'_response'];
        } catch (\Exception $e) {
            throw new Exception($e->getMessage());
        }
    }
    /**
     * @param array $params
     * @return mixed
     */
    private function urlEncodeArray($params) {
        ksort($params);
        $stringToBeSigned = '';
        $i = 0;
        foreach ($params as $k => $v) {
            if (!empty($v) && substr($v, 0, 1) != '@') {
                if ($i == 0) {
                    $stringToBeSigned .= "$k"."=".urlencode($v);
                } else {
                    $stringToBeSigned .= "&"."$k"."=".urlencode($v);
                }
            }
            $i++;
        }
        unset ($k, $v);
        return $stringToBeSigned;
    }

    /**
     * 签名 RSA2
     * @param array $params
     * @return string
     */
    private function sign($params = []) {
        $stringToBeSigned = $this->getSignContent($params);
        $str = chunk_split($this->privKey, 64, "\n");
        $key = "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n";
        openssl_sign($stringToBeSigned, $sign, $key, OPENSSL_ALGO_SHA256);
        return base64_encode($sign);
    }

    /**
     * 签名字符串
     * @param array $params
     * @return string
     */
    private function getSignContent($params) {
        ksort($params);
        $stringToSign = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (empty($params[$k])) {
                continue;
            }
            if ($i == 0) {
                $stringToSign .= "$k"."="."$v";
            } else {
                $stringToSign .= "&"."$k"."="."$v";
            }
            $i++;
        }
        unset ($k, $v);
        return $stringToSign;
    }
}
